open Types
open Utils
open Cfg
open Liveness
open Avail_expr

(** {2 Fonctions générales concernant les analyses à réaliser sur la structure de donnée} *)

(** [print_analyse fp_elt prg] affiche les résultats de l'analyse
  @param fp_elt est une fonction prenant un entier, le label courant, et réalisant l'affichage de l'élément
*)
let rec print_analyse fp_elt prg =
  print_analyse_real fp_elt prg ""
and print_analyse_real fp_elt prg indent = 
  match prg with
  | Skip(l) -> fp_elt l (indent^"Skip") 
  | Assign(x, e,l) -> fp_elt l (indent^(string_of_var x)^" := "^(string_of_expr e))
  | Seq(s1, s2) -> print_analyse_real fp_elt s1 indent ; print_analyse_real fp_elt s2 indent
  | If(c,s1, s2, l) -> fp_elt l (indent^"if("^(string_of_expr c)^") then") ;
                       print_analyse_real fp_elt s1 (indent^"  ");
                       print_endline (indent^"else");
                       print_analyse_real fp_elt s2 (indent^"  ")
  | While(c,s,l) -> fp_elt l (indent^"while("^(string_of_expr c)^") do") ;
                    print_analyse_real fp_elt s (indent^"  ");
  | _ -> failwith "Unknown instr"

(** [backward flw ana_fun lbls curs] réalise une analyse en arrière sur un flot de controle "flw" contenant 
      les labels "lbls" et dont les éléments courants sont "curs"
    @param ana_fun est une fonction prenant un entier, le label de l'instruction courante, et réalisant la 
                   propagation de l'analyse à cette élément
*)
let rec backward ana_fun flw lbls curs =
  match curs with 
    | [] -> ()
    | cur::curs -> ana_fun cur;
                  visited := cur :: (!visited);
                  if check_cycle lbls then
                    ()
                  else begin
                    backward (ana_fun) flw lbls (preds flw cur) ; 
                    backward (ana_fun) flw lbls curs
                  end

(** [forward ana_fun flw lbls curs] réalise une analyse en avant sur un flot de controle "flw" contenant 
      les labels "lbls" et dont les éléments courants sont "curs"
    @param ana_fun est une fonction prenant un entier, le label de l'instruction courante, et réalisant la 
                   propagation de l'analyse à cette élément
*)
let rec forward ana_fun flw lbls curs =
  match curs with 
    | [] -> ()
    | cur::curs -> ana_fun cur;
                  visited := cur :: (!visited);
                  if check_cycle lbls then
                    ()
                  else begin
                    forward (ana_fun) flw lbls curs ;
                    forward (ana_fun) flw lbls (succ flw cur) 
                  end

(** [liveness p] Lance une analyse de variables actives sur le programme "p"*)
let rec liveness p = 
  visited := [];
  let save = !lv_ana in
    let flw = flow p in
      backward (lv p flw) flw (labels p) (final p) ;
      if ln_equal save !lv_ana then
        ()
      else 
        liveness p

(** [liveness p] Lance une analyse des expressions disponibles sur le programme "p"*)
let rec avail_expr p = 
  visited := [];
  let save = !ae_ana in 
    let flw = flow p in 
      forward (ae p flw) flw (labels p) ((init p)::[]) ;
      if ae_equal save !ae_ana then
        ()
      else 
        avail_expr p

(** [analyse p] Lance les analyses et affiche les résultats*)
let analyse p = 
  liveness p ;
  print_endline ("Liveness: ");
  print_analyse (print_liveness !lv_ana) p;
  
  print_endline("");

  avail_expr p;
  print_endline ("Available Expression: ");
  print_analyse (print_avail_expr !ae_ana) p  

